#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/system.h>
#include <asm/io.h>

#define get_seg_byte(seg,addr) ({ \
register char __res; \
__asm__("push %%fs\n\tmov %%ax,%%fs\n\tmovb %%fs:%2,%%al\n\tpop %%fs" \
    :"=a" (__res):"0" (seg),"m" (*(addr))); \
__res;})

#define get_seg_long(seg,addr) ({ \
register unsigned long __res; \
__asm__("push %%fs\n\tmov %%ax,%%fs\n\tmovl %%fs:%2,%%eax\n\tpop %%fs" \
    :"=a" (__res):"0" (seg),"m" (*(addr))); \
__res;})

#define _fs() ({ \
register unsigned short __res; \
__asm__("mov %%fs,%%ax":"=a" (__res):); \
__res;})

int do_exit(long code);

void divide_error(void);
void debug(void);
void nmi(void);
void int3(void);
void overflow(void);
void bounds(void);
void invalid_op(void);
void device_not_available(void);
void double_fault(void);
void coprocessor_segment_overrun(void);
void invalid_TSS(void);
void segment_not_present(void);
void stack_segment(void);
void general_protection(void);
void page_fault(void);
void coprocessor_error(void);
void reserved(void);
void irq13(void);

static void die(char *str, long esp_ptr, long nr)
{
    long *esp = (long *) esp_ptr;
    int i;

    printk("%s: %04x\n\r",str, nr & 0xffff);
    printk("EIP:\t%04x:%p\n\rEFLAGS:\t%p\n\rESP:\t%04x:%p\n\r",
        esp[1], esp[0], esp[2], esp[4], esp[3]);
    printk("fs: %04x\n\r", _fs());
    printk("base: %p, limit: %p\n\r", get_base(current->ldt[1]), get_limit(0x17));
    str(i);
    printk("Pid: %d, process nr: %d\n\r", current->pid, 0xffff & i);
    do_exit(11);
}

void do_double_fault(long esp, long error_code)
{
    die("double fault",esp,error_code);
}

void do_general_protection(long esp, long error_code)
{
    die("general protection",esp,error_code);
}

void do_divide_error(long esp, long error_code)
{
    die("divide error", esp, error_code);
}

void do_int3(long *esp, long error_code,
        long fs, long es, long ds,
        long ebp, long esi, long edi,
        long edx, long ecx, long ebx, long eax)
{
    int tr;

    __asm__("str %%ax":"=a"(tr):"0"(0));    // 获取任务寄存器的值
    printk("eax\t\tebx\t\tecx\t\tedx\n\r%8x\t%8x\t%8x\t%8x\n\r",
        eax, ebx, ecx, edx);
    printk("esi\t\tedi\t\tebp\t\tesp\n\r%8x\t%8x\t%8x\t%8x\n\r",
        esi, edi, ebp, (long) esp);
    printk("\n\rds\tes\tfs\ttr\n\r%4x\t%4x\t%4x\t%4x\n\r",
        ds, es, fs, tr);
    printk("EIP: %8x   CS: %4x  EFLAGS: %8x\n\r",esp[0], esp[1], esp[2]);
}

void do_nmi(long esp, long error_code)
{
    die("nmi", esp, error_code);
}

void do_debug(long esp, long error_code)
{
    die("debug", esp, error_code);
}

void do_overflow(long esp, long error_code)
{
    die("overflow", esp, error_code);
}

void do_bounds(long esp, long error_code)
{
    die("bounds", esp, error_code);
}

void do_invalid_op(long esp, long error_code)
{
    die("invalid operand", esp, error_code);
}

void do_coprocessor_segment_overrun(long esp, long error_code)
{
    die("coprocessor segment overrun", esp, error_code);
}

void do_invalid_TSS(long esp,long error_code)
{
    die("invalid TSS",esp,error_code);
}

void do_segment_not_present(long esp,long error_code)
{
    die("segment not present",esp,error_code);
}

void do_stack_segment(long esp,long error_code)
{
    die("stack segment",esp,error_code);
}

void do_reserved(long esp, long error_code)
{
    die("reserved (15,17-47) error", esp, error_code);
}

void pic_init()
{
    outb_p(0x11, 0x20);    // 边沿触发，多片8259A芯片级联
    outb_p(0x11, 0xa0);    // 边沿触发，多片8259A芯片级联
    outb_p(0x20, 0x21);    // 主片中断请求0~7对应的中断号是0x20~0x27
    outb_p(0x28, 0xa1);    // 从片中断请求8~15级对应的中断号是0x28~0x2f
    outb_p(0x04, 0x21);    // 主片的IR2连接一个从片
    outb_p(0x02, 0xa1);    // 从片连接到主片的IR2引脚
    outb_p(0x01, 0x21);    // 普通全嵌套方式、非缓冲方式、非自动结束中断方式
    outb_p(0x01, 0xa1);    // 普通全嵌套方式、非缓冲方式、非自动结束中断方式
    outb_p(0xff, 0x21);    // 屏蔽所有中断
    outb_p(0xff, 0xa1);    // 屏蔽所有中断
}

void trap_init(void)
{
    int i;
    pic_init();
    set_trap_gate(0, &divide_error);
    set_trap_gate(1, &debug);
    set_trap_gate(2, &nmi);
    set_system_gate(3, &int3);    /* int3-5 can be called from all */
    set_system_gate(4, &overflow);
    set_system_gate(5, &bounds);
    set_trap_gate(6, &invalid_op);
    set_trap_gate(7, &device_not_available);
    set_trap_gate(8, &double_fault);
    set_trap_gate(9, &coprocessor_segment_overrun);
    set_trap_gate(10, &invalid_TSS);
    set_trap_gate(11, &segment_not_present);
    set_trap_gate(12, &stack_segment);
    set_trap_gate(13, &general_protection);
    set_trap_gate(14, &page_fault);
    set_trap_gate(15, &reserved);
    set_trap_gate(16, &coprocessor_error);
    for (i = 17; i < 48; i++)
        set_trap_gate(i, &reserved);
    set_trap_gate(45, &irq13);
    outb_p(inb_p(0x21) & 0xfb, 0x21);
    outb(inb_p(0xA1) & 0xdf, 0xA1);
}
